面试题 08.06. 汉诺塔问题
面试题 08.06. 汉诺塔问题
Similar Question
Solution Tips
方案一: 递归
有 A,B,C 三根柱子,A 上面有 n 个盘子,我们想把 A 上面的盘子移动到 C 上,但是要满足以下三个条件:
- 每次只能移动一个盘子;
- 盘子只能从柱子顶端滑出移到下一根柱子;
- 盘子只能叠在比它大的盘子上。
这是一道递归方法的经典题目,乍一想还挺难理清头绪的,我们不妨先从简单的入手。
假设 n = 1,只有一个盘子,很简单,直接把它从 A 中拿出来,移到 C 上;
如果 n = 2 呢?这时候我们就要借助 B 了,因为小盘子必须时刻都在大盘子上面,共需要 4 步。
如果 n > 2
呢?思路和上面是一样的,我们把 n 个盘子也看成两个部分,一部分有 1 个盘子,另一部分有 n - 1 个盘子。
注意,当你在思考这个问题的时候,就将最初的 n 个盘子从 A 移到 C 的问题,转化成了将 n - 1 个盘子从 A 移到 C 的问题, 依次类推,直至转化成 1 个盘子的问题时,问题也就解决了。这就是分治的思想。
而实现分治思想的常用方法就是递归。不难发现,如果原问题可以分解成若干个与原问题结构相同但规模较小的子问题时,往往可以用递归的方法解决。具体解决办法如下:
- n = 1 时,直接把盘子从 A 移到 C;
- n > 1 时,
- 先把上面 n - 1 个盘子从 A 移到 B(子问题,递归);
- 再将最大的盘子从 A 移到 C;
- 再将 B 上 n - 1 个盘子从 B 移到 C(子问题,递归)。
const hanota = (A, B, C) => {
const n = A.length;
// 将 A 中的 n 个移动到 C
const move = (n, A, B, C) => {
if (n === 1) {
C.push(A.pop());
return;
}
// 将 A 中的 n-1 个移动到 B
move(n - 1, A, C, B);
// 将 A 剩余的 n 移动到 C
C.push(A.pop());
// 将 B 中的 n-1 个移动到 C
move(n - 1, B, A, C);
};
move(n, A, B, C);
};